package com.thermofisher.dsc.amanda.common.crud.service;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.thermofisher.dsc.amanda.common.BaseMapper;
import com.thermofisher.dsc.amanda.common.Query;
import com.thermofisher.dsc.amanda.common.crud.Util;
import com.thermofisher.dsc.amanda.model.BaseModel;
import com.thermofisher.dsc.amanda.model.response.PageResponse;
import java.util.ArrayList;
import java.util.List;

import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;


/**
 * @author yunpeng.song
 */
public abstract class AbsBaseService<T, P, M extends BaseMapper<P>> implements BaseService<T> {

    protected M mapper;

    public AbsBaseService(M mapper) {
        this.mapper = mapper;
    }


    protected <X> X convert(Object s, Class<X> klass) {
        return Util.convert(s, klass);
    }

    protected <X, Y> Y convert(X x, Y y) {
        return Util.convert(x, y);
    }

    protected P dtoToPo(T t) {
        return convert(t, (Class<P>) Util.getActualArgumentType(getClass(), 1));
    }

    protected T poToDto(P p) {
        return poToDto(p, null);
    }

    protected T poToDto(P p, T t) {
        if (t == null) {
            t = Util.createInstance(Util.getActualArgumentType(getClass(), 0));
        }
        convert(p, t);
        return t;
    }

    protected void insertCheck(T t) {
        //
    }

    protected void updateCheck(T t) {
        //
    }


    @Transactional
    @Override
    public T create(T t) {
        insertCheck(t);
        P p = dtoToPo(t);
        // Util.populateAuditInfo((BaseModel) p, true);
        mapper.insertSelective(p);
        poToDto(p, t);
        return t;
    }

    /*@Transactional(rollbackFor = Exception.class)
    @Override
    public void createList(List<T> tlist) {
        if (tlist == null) {
            return;
        }
        List<P> plist = new ArrayList<>();
        tlist.forEach(t -> {
            P p = dtoToPo(t);
            plist.add(p);
        });
        mapper.insertList(plist);
    }*/

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteListByIds(List<Long> ids) {
        if (ids == null) {
            return;
        }
        Example example = new Example(Util.getActualArgumentType(getClass(), 1));
        Example.Criteria criteria = example.createCriteria();
        criteria.andIn(Query.ID, ids);
        mapper.deleteByExample(example);
    }


    @Transactional
    @Override
    public T update(T t) {
        updateCheck(t);
        P p = dtoToPo(t);
        Util.populateAuditInfo((BaseModel) p, false);
        mapper.updateByPrimaryKeySelective(p);
        return t;
    }

    @Transactional
    @Override
    public void delete(Long id) {
        mapper.deleteByPrimaryKey(id);
    }


    @Override
    public PageResponse getList(Query query) {
        Example example = this.buildDefaultAndCriteria(query, Util.getActualArgumentType(getClass(), 1));
        Page<Object> result = null;
        if (query.isOnepage()) {
            result = new Page<>();
            result.addAll(mapper.selectByExample(example));
            result.setPageNum(query.getPage());
            result.setPageSize(query.getLength());
            result.setTotal(result.size());
        } else {
            result = PageHelper.startPage(query.getPage(), query.getLength());
            mapper.selectByExample(example);
        }

        List<P> plist = (List<P>) result.getResult();
        List<T> tlist = new ArrayList<>();
        if (plist != null) {
            plist.stream().forEach(p -> {
                    tlist.add(poToDto(p));
                }
            );
        }
        int dataBaseTotal = mapper.selectCount(null);
        return new PageResponse(query.getPage(), query.getLength(), result.getTotal(),null,
            tlist);
    }

    @Override
    public int getListCount(Query query) {
        Example example = this.buildDefaultAndCriteria(query, Util.getActualArgumentType(getClass(), 1));
        return mapper.selectCountByExample(example);
    }


    @Override
    public T getById(Long id) {
        return poToDto(mapper.selectByPrimaryKey(id));
    }

}